﻿using System;
using System.Collections.Generic;

namespace XEvolve.Core
{
    public abstract class Plugin
    {        
        public class ExtensionPoint
        {
            internal ExtensionPoint() { }
            public object Identifier { get; internal set; }
            public bool IsCachingExtension { get; internal set; }
            internal Type Plugin { get; set; }
        }
        public sealed class ExtensionPoint<ExtensionType> : ExtensionPoint
        {
            internal ExtensionPoint() { }         
        }

        public sealed class ExtensionPoint<ExtensionIdentifierType, ExtensionType> : ExtensionPoint
        {
            internal ExtensionPoint() { }
        }

        public sealed class ExtensionImplementation<ImplementationType>
        {
            internal ExtensionImplementation() { }
            public Type Type { get { return typeof(ImplementationType); } }
        }

        protected static ExtensionPoint<ExtensionType> DefineExtensionPoint<ExtensionType>(object identifier, bool isCachingExtension)
        {
            return new ExtensionPoint<ExtensionType> {Identifier = identifier, IsCachingExtension = isCachingExtension};
        }

        protected static ExtensionPoint<ExtensionIdentifierType, ExtensionType> DefineExtensionPoint<ExtensionIdentifierType, ExtensionType>(object identifier, bool isCachingExtension)
        {
            return new ExtensionPoint<ExtensionIdentifierType, ExtensionType> { Identifier = identifier, IsCachingExtension = isCachingExtension };
        }

        protected static ExtensionImplementation<ImplementationType> Implementation<ImplementationType>()
        {
            return new ExtensionImplementation<ImplementationType>();
        }

        internal IList<Type> dependencies = new List<Type>();

        protected void Register<ExtensionType, ImplementationType>(ExtensionPoint<ExtensionType> extensionPoint, ExtensionImplementation<ImplementationType> implementation) where ImplementationType : ExtensionType
        {
            Platform.Current.platformProvider.ExtensionRegistry.RegisterExtension(extensionPoint.Identifier, implementation.Type);
            dependencies.Add(extensionPoint.Plugin);
        }
        protected void Register<ExtensionType>(ExtensionPoint<ExtensionType> extensionPoint, ExtensionType instance)
        {
            Platform.Current.platformProvider.ExtensionRegistry.RegisterExtension(extensionPoint.Identifier, instance);
            dependencies.Add(extensionPoint.Plugin);
        }
        protected void Register<ExtensionIdentifierType, ExtensionType, ImplementationType>(ExtensionPoint<ExtensionIdentifierType, ExtensionType> extensionPoint, ExtensionIdentifierType identifier, ExtensionImplementation<ImplementationType> implementation) where ImplementationType : ExtensionType
        {
            Platform.Current.platformProvider.ExtensionRegistry.RegisterExtension(extensionPoint.Identifier, identifier, implementation.Type);
            dependencies.Add(extensionPoint.Plugin);
        }
        protected void Register<ExtensionIdentifierType, ExtensionType>(ExtensionPoint<ExtensionIdentifierType, ExtensionType> extensionPoint, ExtensionIdentifierType identifier, ExtensionType instance)
        {
            Platform.Current.platformProvider.ExtensionRegistry.RegisterExtension(extensionPoint.Identifier, identifier, instance);
            dependencies.Add(extensionPoint.Plugin);
        }
        protected void RegisterService<Api>(Api instance)
        {
            Platform.Current.platformProvider.ServiceRegistry.RegisterService(typeof(Api), instance);
        }
        protected void RegisterService<Api, Implementation>() where Implementation : Api
        {
            Platform.Current.platformProvider.ServiceRegistry.RegisterService(typeof(Api), typeof(Implementation));
        }

        public abstract void Initialize();
    }
}
